#include "fr30xx.h"

/* FreeRTOS kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"

#include "co_util.h"

/* little file system  */
#include "lfs_port.h"

/* LVGL includes */
#include "demos/lv_demos.h"

#include "heap.h"
#include "app_config.h"
#include "app_lvgl.h"
#include "app_hw.h"
#include "img_def.h"
#include "IC_W25Qxx.h"
#include "app_task.h"

#include "driver_st7282_rgb_hw.h"
#include "driver_display_dev.h"
// #include "driver_touchpad.h"
// #include "driver_psram.h"
#include "fr_device_rtc.h"
#include "fr_device_encode.h"
// #include "fr_device_vbat.h"

// #include "driver_st7701_rgb.h"

//task queue
#define GUI_TASK_QUEUE_LENGTH		( 64 )

#define SYS_TASK_QUEUE_LENGTH		( 64 )

//lvgl define
#if BOARD_SEL == BOARD_EVB_FR5090
#define LCD_HOR_SIZE            (466)
#define LCD_VER_SIZE            (466)
#elif BOARD_SEL == BOARD_EVB_FR3092E
    #if  0  //DISPLAY_TYPE_ICNA3310
    #define LCD_HOR_SIZE            (466)
    #define LCD_VER_SIZE            (466)
    #else
    #define LCD_HOR_SIZE            (368)
    #define LCD_VER_SIZE            (448)
    #endif
#elif BOARD_SEL == BOARD_EVB_FR3092E_CM
#define LCD_HOR_SIZE            (368)
#define LCD_VER_SIZE            (448)

#elif BOARD_SEL == BOARD_EVB_FR3092E_RGB
#define LCD_HOR_SIZE            LV_HOR_RES_MAX
#define LCD_VER_SIZE            LV_VER_RES_MAX

//#define PSRAM_FOR_LCD_GRAM

#else
#error "choose correct board"
#endif



#if (((LCD_HOR_SIZE - LV_HOR_RES_MAX) / 2 ) & 0x01)
    #define HOR_OFFSET          (((LCD_HOR_SIZE - LV_HOR_RES_MAX) / 2 ) + 0x01)
#else
    #define HOR_OFFSET          (((LCD_HOR_SIZE - LV_HOR_RES_MAX) / 2 ) + 0x00)
#endif
#if (((LCD_VER_SIZE - LV_VER_RES_MAX) / 2 ) & 0x01)
    #define VER_OFFSET          (((LCD_VER_SIZE - LV_VER_RES_MAX) / 2 ) + 0x01)
#else
    #define VER_OFFSET          (((LCD_VER_SIZE - LV_VER_RES_MAX) / 2 ) + 0x00)
#endif


#define LV_HOR_RES_MAX_ZOOM  258
#define LV_VER_RES_MAX_ZOOM  314 


DMA_HandleTypeDef dma_psram_handle;

/* used for DMA display */
volatile bool display_dma_ongoing = false;

/* LVGL display buf enviroment */
static lv_disp_draw_buf_t disp_buf;
static lv_disp_drv_t * last_disp;
lv_indev_t * indev_keypad;
uint8_t key_code;

//default display buffer size : 480 * 480 * 16 / 8
#define DEFAULT_DISP_ROW_COL  (480 * 272)
#ifdef DISPLAY_TYPE_ST7282_RGB_HW
#define DISP_BUFFER_COL    (DEFAULT_DISP_ROW_COL / LV_HOR_RES_MAX)
#define   DISPLAY_BUFFER_SIZE   LV_HOR_RES_MAX*DISP_BUFFER_COL*LV_COLOR_DEPTH/8/sizeof(uint32_t)
#define   DISPLAY_PSRAM_SIZE   LV_HOR_RES_MAX*LV_VER_RES_MAX*LV_COLOR_DEPTH/8
#define   DISPLAY_BLOCK_LINE  DECODE_LINE_NUMBER
#define   DISPLAY_BUFFER_20_LINE   LV_HOR_RES_MAX*DISPLAY_BLOCK_LINE*LV_COLOR_DEPTH/8/sizeof(uint32_t)
uint32_t framebuffer_block_len = (DISPLAY_BUFFER_20_LINE+16) << 2;
__attribute__((section("dram_sec"))) uint32_t display_framebuffer_block[DISPLAY_BUFFER_20_LINE];
//#define DRAW_BUFFER_LINE	LV_VER_RES_MAX/2
#define DRAW_BUFFER_LINE	100 //280

// uint32_t display_framebuffer[LV_HOR_RES_MAX*DRAW_BUFFER_LINE/2];
// uint32_t display_framebuffer1[DISPLAY_BUFFER_SIZE];
#define FRAME_BUFFER_SIZE   (0x80000 - (LV_HOR_RES_MAX * DISP_BUFFER_COL * 2))
#define FRAME_BUFFER  (void *)(0x20000000 + FRAME_BUFFER_SIZE)
#define REFR_BUFFER   (void *)(0x20000000 +(FRAME_BUFFER_SIZE - (LV_HOR_RES_MAX * DRAW_BUFFER_LINE * 2)))

void * display_framebuffer;
void * display_framebuffer1;
#endif

#define LOAD_ORIG_FRAMEBUFFER       (void *)(PSRAM_DAC_BASE+ 60 + DISPLAY_PSRAM_SIZE)
#define LOAD_LEFT_FRAMEBUFFER       (void *)(PSRAM_DAC_BASE+ 60 + DISPLAY_PSRAM_SIZE*2)
#define LOAD_RIGHT_FRAMEBUFFER      (void *)(PSRAM_DAC_BASE+ 60 + DISPLAY_PSRAM_SIZE*3)


static QueueHandle_t gui_queue_handle;
static QueueHandle_t app_queue_handle;
static TaskHandle_t gui_task_Handle = NULL;


#define LV_FRAME_API
#ifdef LV_FRAME_API
const lv_img_dsc_t fetch_orig_psram_img = {
  .header.always_zero = 0,
  .header.w = LV_HOR_RES_MAX,
  .header.h = LV_VER_RES_MAX,
  .data_size = LV_HOR_RES_MAX * LV_VER_RES_MAX * LV_COLOR_SIZE / 8,
  .header.cf = LV_IMG_CF_TRUE_COLOR,
  .header.reserved = 0,
  .data = (const uint8_t *)LOAD_ORIG_FRAMEBUFFER,
};

const lv_img_dsc_t fetch_disp_buf_psram_img = {
  .header.always_zero = 0,
  .header.w = LV_HOR_RES_MAX,
  .header.h = LV_VER_RES_MAX,
  .data_size = LV_HOR_RES_MAX * LV_VER_RES_MAX * LV_COLOR_SIZE / 8,
  .header.cf = LV_IMG_CF_TRUE_COLOR,
  .header.reserved = 0,
  .data =  (const uint8_t *)LOAD_LEFT_FRAMEBUFFER,
};


const lv_img_dsc_t fetch_orig_img = {
  .header.always_zero = 0,
  .header.w = LV_HOR_RES_MAX,
  .header.h = LV_VER_RES_MAX,
  .data_size = LV_HOR_RES_MAX * LV_VER_RES_MAX * LV_COLOR_SIZE / 8,
  .header.cf = LV_IMG_CF_TRUE_COLOR,
  .header.reserved = 0,
  .data = NULL,//(const uint8_t *)display_framebuffer1,//(void *)PSRAM_DAC_BASE,
};

const lv_img_dsc_t fetch_orig_zoom_img = {
  .header.always_zero = 0,
  .header.w = LV_HOR_RES_MAX_ZOOM,
  .header.h = LV_VER_RES_MAX_ZOOM,
  .data_size = LV_HOR_RES_MAX_ZOOM * LV_VER_RES_MAX_ZOOM * LV_COLOR_SIZE / 8,
  .header.cf = LV_IMG_CF_TRUE_COLOR,
  .header.reserved = 0,
  .data = NULL,//(const uint8_t *)display_framebuffer1,//(void *)PSRAM_DAC_BASE,
};


const lv_img_dsc_t fetch_disp_buf_img = {
  .header.always_zero = 0,
  .header.w = LV_HOR_RES_MAX,
  .header.h = LV_VER_RES_MAX,
  .data_size = LV_HOR_RES_MAX * LV_VER_RES_MAX * LV_COLOR_SIZE / 8,
  .header.cf = LV_IMG_CF_TRUE_COLOR,
  .header.reserved = 0,
  .data =  NULL,//(const uint8_t *)display_framebuffer,
};


const lv_img_dsc_t fetch_disp_buf_zoom_img = {
  .header.always_zero = 0,
  .header.w = LV_HOR_RES_MAX_ZOOM,
  .header.h = LV_VER_RES_MAX_ZOOM,
  .data_size = LV_HOR_RES_MAX_ZOOM * LV_VER_RES_MAX_ZOOM * LV_COLOR_SIZE / 8,
  .header.cf = LV_IMG_CF_TRUE_COLOR,
  .header.reserved = 0,
  .data = NULL,//(const uint8_t *)display_framebuffer1 + (LV_HOR_RES_MAX * LV_VER_RES_MAX)
};

extern bool fetch_orig_buffer_flag;
extern bool fetch_orig_buffer_zoom_flag;
extern bool exit_disp_flush_flag;
extern bool fetch_disp_buffer_flag;
extern bool fetch_disp_buffer_zoom_flag;

void lv_disp_buffer_copy(void)
{

    //fputc('<', NULL);
    volatile uint32_t * dst = display_framebuffer1;
    volatile uint32_t * src = display_framebuffer;
    for (uint32_t i=0; i<DISPLAY_PSRAM_SIZE/sizeof(uint32_t); i++) {
        *dst++ = *src++;
    }
    //fputc('>', NULL);
}

bool lv_fetch_disp_buffer_func(const lv_area_t * area)
{
	return false;
}

void lv_disp_buffer_psram_copy(void)
{

    //fputc('{', NULL);
    volatile uint32_t * dst = LOAD_ORIG_FRAMEBUFFER;
    volatile uint32_t * src = display_framebuffer;
    for (uint32_t i=0; i<DISPLAY_PSRAM_SIZE/sizeof(uint32_t); i++) {
        *dst++ = *src++;
    }
    //fputc('}', NULL);
}

bool lv_fetch_disp_buffer_psram_func(const lv_area_t * area)
{
	return false;
}

void lv_obj_set_scroll_anim_time(lv_coord_t min,lv_coord_t max)
{
    // lv_scroll_anim_time_min = min;
    // lv_scroll_anim_time_max = max;
}
#endif


static void setup_gui_running(void);

//----------------------------------------------------
//lvgl function
//----------------------------------------------------
// this function is when frame data is flushed
static void my_disp_flush_done(void)
{
    lv_disp_flush_ready(last_disp);
}


extern bool display_te_status(void);
extern uint8_t volatile te_sign;
extern void stop_refresh_timer(void);
extern void start_refresh_timer(void);
extern void lv_prj_main(void);
#include <stdio.h>

__RAM_CODE static void my_disp_flush(lv_disp_drv_t * disp, const lv_area_t * area, lv_color_t * color_p)
{

	#if BOARD_SEL == BOARD_EVB_FR3092E_RGB

    // while(!te_sign)
    // {
    //     //vTaskDelay(1);
    // }

	// if(area->y1 == 0)
    // {
	// 	stop_refresh_timer();
    // }

    //printf("area->y1 : %d \n",area->y1);

	uint16_t width = area->x2 - area->x1 + 1;
	uint16_t height = area->y2 - area->y1 + 1;
    uint16_t y_offset;
	for (uint16_t i = area->y1; i <= area->y2; i++) {
        if(i >= DISP_BUFFER_COL){
            y_offset = i - DISP_BUFFER_COL;
        }
        else
            y_offset = i;
		uint16_t *pColor = &(((uint16_t*)display_framebuffer1)[y_offset * LV_HOR_RES_MAX]);
		uint16_t *src = &color_p[(i - area->y1) * width + (area->x1 - area->x1)].full;
		memcpy(pColor + area->x1, src, width * sizeof(uint16_t));
	}

    // if(((area->y1 % DRAW_BUFFER_LINE) == 0)
    //     ||(area->y2 == (LV_VER_RES_MAX-1)))
    // if(area->y2 == (LV_VER_RES_MAX-1))
	// {
	//    start_refresh_timer();
	// }
	lv_disp_flush_ready(disp);

    #else

	    while(display_dma_ongoing);
    system_prevent_sleep_set(SYSTEM_PREVENT_SLEEP_DISPLAY_ONGOING);
    display_dma_ongoing = true;
    last_disp = disp;

    while(!display_te_status());

    display_set_window(HOR_OFFSET+area->x1, 
                        HOR_OFFSET+area->x2, 
                        VER_OFFSET+area->y1, 
                        VER_OFFSET+area->y2);

    #if LV_COLOR_DEPTH == 16
    display_update_dma((area->x2+1-area->x1)*(area->y2+1-area->y1), 16, (void *)color_p);
    #elif LV_COLOR_DEPTH == 32
    display_update_dma((area->x2+1-area->x1)*(area->y2+1-area->y1), 32, (void *)color_p);
    #endif

    #endif
}

static void my_touchpad_read(struct _lv_indev_drv_t * indev, lv_indev_data_t * data)
{

    int16_t x, y;
    bool pressed;
    
    pressed = 0;//touchpad_read(&x, &y);
    if (pressed) {
        if ((x < HOR_OFFSET) 
                || (x >= HOR_OFFSET + LV_HOR_RES_MAX)
                || (y < VER_OFFSET)
                || (y >= (VER_OFFSET + LV_VER_RES_MAX))) {
            data->state = LV_INDEV_STATE_REL;
        }
        else {
            data->state = LV_INDEV_STATE_PR;
            
            data->point.x = x - HOR_OFFSET;
            data->point.y = y - VER_OFFSET;
            //printf("x:%d,y:%d\n",data->point.x,data->point.y);
        }
        setup_gui_running();
    }
    else 
    {
        data->state = LV_INDEV_STATE_REL;
    }
}

static uint32_t keypad_get_key(void)
{
    /*Your code comes here*/

    return key_code;
}

/*Will be called by the library to read the mouse*/
static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
    static uint32_t last_key = 0;

    /*Get the current x and y coordinates*/
    //mouse_get_xy(&data->point.x, &data->point.y);

    /*Get whether the a key is pressed and save the pressed key*/
    uint32_t act_key = keypad_get_key();
    if(act_key != 0) {
        data->state = LV_INDEV_STATE_PR;

        /*Translate the keys to LVGL control characters according to your key definitions*/
        switch(act_key) {
        case 1:
            act_key = LV_KEY_NEXT;
            break;
        case 2:
            act_key = LV_KEY_PREV;
            break;
        case 3:
            act_key = LV_KEY_LEFT;
            break;
        case 4:
            act_key = LV_KEY_RIGHT;
            break;
        case 5:
            act_key = LV_KEY_ENTER;
            break;
        }

        last_key = act_key;
		
		key_code = 0;
        //printf("%d keydown \n",last_key);
    } else {
        data->state = LV_INDEV_STATE_REL;
    }

    data->key = last_key;
}


bool touchpad_state(void)
{
    int16_t x, y;
    return false;//touchpad_read(&x, &y);
}

static void lvgl_init(void)
{

    display_framebuffer = REFR_BUFFER;
    display_framebuffer1 = FRAME_BUFFER;

    lv_init();

    lv_disp_draw_buf_init(&disp_buf, (void *)display_framebuffer, NULL, LV_HOR_RES_MAX * DRAW_BUFFER_LINE);    /*Initialize the display buffer*/
	//lv_disp_draw_buf_init(&disp_buf, (void *)display_framebuffer1, NULL, LV_HOR_RES_MAX * LV_HOR_RES_MAX);

    /* Implement and register a function which can copy the rendered image to an area of your display */
    static lv_disp_drv_t disp_drv;          /*Descriptor of a display driver*/
    lv_disp_drv_init(&disp_drv);            /*Basic initialization*/
    disp_drv.flush_cb = my_disp_flush;      /*Set your driver function*/
    disp_drv.draw_buf = &disp_buf;          /*Assign the buffer to the display*/
    disp_drv.hor_res = LV_HOR_RES_MAX;
    disp_drv.ver_res = LV_VER_RES_MAX;
    disp_drv.physical_hor_res = -1;
    disp_drv.physical_ver_res = -1;
    disp_drv.offset_x = 0;
    disp_drv.offset_y = 0;
    disp_drv.full_refresh = 0;
    lv_disp_drv_register(&disp_drv);        /*Finally register the driver*/
    /* Implement and register a function which can read an input device. E.g. for a touch pad */
    
	static lv_indev_drv_t indev_drv;        /*Descriptor of a input device driver*/
    lv_indev_drv_init(&indev_drv);          /*Basic initialization*/
    indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/
    indev_drv.read_cb = my_touchpad_read;   /*Set your driver function*/
    lv_indev_drv_register(&indev_drv);      /*Finally register the driver*/

#if 1
    /*------------------
     * Keypad
     * -----------------*/

   static lv_indev_drv_t indev_drv1;

    /*Initialize your keypad or keyboard if you have*/
    //keypad_init();

    /*Register a keypad input device*/
    lv_indev_drv_init(&indev_drv1);
    indev_drv1.type = LV_INDEV_TYPE_KEYPAD;
    indev_drv1.read_cb = keypad_read;
    indev_keypad = lv_indev_drv_register(&indev_drv1);

    /*Later you should create group(s) with `lv_group_t * group = lv_group_create()`,
     *add objects to the group with `lv_group_add_obj(group, obj)`
     *and assign this input device to group to navigate in it:
     *`lv_indev_set_group(indev_keypad, group);`*/

#endif

//    lv_demo_benchmark();
//    lv_demo_stress();
//    lv_demo_widgets();
//    lv_demo_music();
	//lv_demo_benchmark();
     lv_prj_main();

}
//----------------------------------------------------
//end
//----------------------------------------------------

int gui_task_msg_send(uint16_t msg_type,
                    void *header,
                    uint16_t header_length,
                    uint8_t *payload,
                    uint16_t payload_length,
                    ipc_tx_callback callback)
{
	gui_task_msg_t queue_event;

	queue_event.msg_type = msg_type;
	queue_event.param_len = header_length+payload_length;
    memcpy(queue_event.param, header, header_length);
    memcpy(queue_event.param+header_length, payload, payload_length);

    //if (portNVIC_INT_CTRL_REG & 0xff)
    if(xPortIsInsideInterrupt()) 
    {
        BaseType_t xTaskWokenByPost = pdFALSE;

        if (xQueueSendFromISR(gui_queue_handle, &queue_event, &xTaskWokenByPost) ==  errQUEUE_FULL ) 
        {
            return -1;
        } 
        else
        {
            portYIELD_FROM_ISR(xTaskWokenByPost);
        }
    } 
    else 
    {
    	if (xQueueSend(gui_queue_handle, &queue_event, ( TickType_t ) 0) != pdPASS) 
        {
            return -1;
    	}
    }

	return 0;
}

int sync_task_msg_send(uint16_t msg_type,
                    void *header,
                    uint16_t header_length,
                    uint8_t *payload,
                    uint16_t payload_length,
                    ipc_tx_callback callback)
{
	gui_task_msg_t queue_event;

	queue_event.msg_type = msg_type;
	queue_event.param_len = header_length+payload_length;
    memcpy(queue_event.param, header, header_length);
    memcpy(queue_event.param+header_length, payload, payload_length);

    //if (portNVIC_INT_CTRL_REG & 0xff) 
    if(xPortIsInsideInterrupt()) 
    {
        BaseType_t xTaskWokenByPost = pdFALSE;

        if (xQueueSendFromISR(app_queue_handle, &queue_event, &xTaskWokenByPost) ==  errQUEUE_FULL ) 
        {
            return -1;
        } 
        else
        {
            portYIELD_FROM_ISR(xTaskWokenByPost);
        }
    } 
    else 
    {
    	if (xQueueSend(app_queue_handle, &queue_event, ( TickType_t ) 0) != pdPASS) 
        {
            return -1;
    	}
    }

	return 0;
}


uint32_t gui_running_last_time;
bool gui_task_resume_flag = false;
bool gui_task_suspend_flag = false;
static void setup_gui_running(void)
{
    gui_running_last_time = portGET_RUN_TIME_COUNTER_VALUE();
}

static uint32_t get_gui_running_basetime(void)
{
	uint32_t cur_base_time = portGET_RUN_TIME_COUNTER_VALUE();
    uint32_t diff;
    if(cur_base_time >= gui_running_last_time)
        diff = cur_base_time - gui_running_last_time;
    else
        diff = (((uint32_t)0xFFFFFFFF)  - gui_running_last_time) + cur_base_time + 1;

	return diff;
}

bool screensaver_lock_flags = false;
const uint8_t sec_item_value[] = {5,10,15,20,25,35,40,45,50,60,120,180,240};
uint32_t backlight_delay_counter;
bool backlight_delay_enable = false;
static void gui_task_auto_suspend(void)
{
    if(get_gui_running_basetime() > (sec_item_value[12] * 1000) || gui_task_suspend_flag)
    {
        lv_obj_add_flag(lv_scr_act(),LV_OBJ_FLAG_HIDDEN);
        while(display_dma_ongoing)
        {
            vTaskDelay(1);
        }
        setup_gui_running();
        display_power_off();
        // touchpad_sleep();
        vTaskSuspend(gui_task_Handle);
        gui_task_suspend_flag = false;
    }
    
    if(gui_task_resume_flag)
    {
        gui_task_resume_flag = false;
        lv_obj_clear_flag(lv_scr_act(),LV_OBJ_FLAG_HIDDEN);
        backlight_delay_counter = lv_tick_get();
        backlight_delay_enable = true;
        
    }

}

bool gui_task_suspend_state(void)
{
    return gui_task_suspend_flag;
}

void gui_task_suspend(void)
{
    //vTaskSuspend(gui_task_Handle);
    gui_task_suspend_flag = true;
}

void * gui_task_handle_is_active(void)
{
    return gui_task_Handle;
}


bool gui_task_resume(void)
{
    setup_gui_running();
    if( eTaskGetState( gui_task_Handle ) == eSuspended)
    {
        // touchpad_init();
        display_power_on();
        vTaskResume(gui_task_Handle);
        gui_task_resume_flag = true;
        return true;
    }
    return false;
}

void app_task_wakeup_gui_task(void)
{
	struct app_task_event *event;
	event = app_task_event_alloc(APP_TASK_EVENT_WAKEUP_GUITASK, 0, false);
	if(event) 
	{
		//memcpy(event->param, (void *)&curr_button, sizeof(uint32_t));
		//event->param_len = sizeof(uint32_t);
		app_task_event_post(event, false);
	}
}


int32_t tick_counter = 0;
//#define TEST_FLASH_WR
#ifdef TEST_FLASH_WR
#define TEST_LEN  256
uint8_t test_psram[TEST_LEN];

uint8_t checksum(uint8_t *buffer, uint32_t len)
{
    uint8_t sum = 0;
    for(uint32_t i = 0; i < len; i++)
    {
        sum += buffer[i];
    }
    return sum;
}
#endif

//gui task
static void gui_task(void *arg)
{
    gui_task_msg_t queue_event;
	
    printf("gui_task \r\n");
        
    /* lfs init */
    lfs_custom_init();
    //lfs_custom_test_write_file();
    //lfs_custom_test();

    #ifdef TEST_FLASH_WR
    //test falsh w/r
    // IC_W25Qxx_EraseSector(0);
    // memset((void *)test_psram,0x5a,50);
    // //extern_flash_write(test_psram, 0, 50);
    // IC_W25Qxx_PageProgram(test_psram, 0, 50);
    // memset((void *)test_psram,0,50);
    // extern_flash_read(test_psram,0,50);
	// for(uint32_t i=0;i<(50);i++)
	// {
	// 	printf("%x ",test_psram[i]);
	// }

    uint32_t src_addr;
    uint32_t start_addr;
    uint32_t length;
    uint8_t check;
    extern uint8_t IMG_ROM_BASE, IMG_ROM_END;
    src_addr = (uint32_t)&IMG_ROM_BASE;
    length = (uint32_t)&IMG_ROM_END - (uint32_t)&IMG_ROM_BASE;
    extern void ext_flash_erase(uint32_t addr, uint32_t len);
    ext_flash_erase(0,length);
    start_addr = 0;
    while(length > 0)
    {
        memcpy(test_psram,(uint8_t *)src_addr,TEST_LEN);
        check = checksum(test_psram,TEST_LEN);
        //printf("0x%x %",check);
        //IC_W25Qxx_PageProgram(test_psram, start_addr, TEST_LEN);
        extern_flash_write(test_psram, start_addr, TEST_LEN);

        memset((void *)test_psram,0,TEST_LEN);
        extern_flash_read(test_psram,start_addr,TEST_LEN);
        if(checksum(test_psram,TEST_LEN) != check)
        {
            fputc('e',NULL);
        }

        src_addr += TEST_LEN;
        start_addr += TEST_LEN;
        if(length < TEST_LEN)
            length = 0;
        else
            length -= TEST_LEN;

    }
    #endif

    //dev_rtc_time_init();
	vTaskDelay(200);
    lvgl_init();

	// Create  queue for gui task
	gui_queue_handle = xQueueCreate(GUI_TASK_QUEUE_LENGTH, sizeof(gui_task_msg_t));

    //battery detect
   // adc_vbat_start_detect();
  
    setup_gui_running();

    display_dev_init();

	printf("gui_task running ...\r\n");
    while(1) {
        vTaskDelay(1);
        lv_timer_handler();
        rtc_running();
       // encode_key_release();
        
 		if (xQueueReceive(gui_queue_handle, &queue_event, 0) == pdPASS) 
        {
            gui_task_queue_callback(&queue_event);
        }
        int32_t tick_get = lv_tick_get() / 1000;
		if(tick_get != tick_counter)
        {
            tick_counter = tick_get;
            fputc('>',NULL);
            // printf("lvgl tick\r\n");
// //			i2c_memory_read(&i2c_touchpad_handle, (0x71) , 0x02, buffer, 1);
// //			printf("sta:%x\r\n",buffer[0]);
            // printf("MEM usage\r\n \
            //                 \tHEAP_TYPE_SRAM_BLOCK: %d, %d, %d\r\n \
            //                 \tHEAP_TYPE_DRAM_BLOCK: %d, %d, %d\r\n \
            //                 \tHEAP_TYPE_BTDM_BLOCK: %d, %d, %d\r\n \
            //                 \tTOTAL USAGE: %d\r\n", \
            //                     heap_get_mem_usage(HEAP_TYPE_SRAM_BLOCK), heap_get_max_mem_usage_single(HEAP_TYPE_SRAM_BLOCK), heap_get_mem_available(HEAP_TYPE_SRAM_BLOCK), \
            //                     heap_get_mem_usage(HEAP_TYPE_DRAM_BLOCK), heap_get_max_mem_usage_single(HEAP_TYPE_DRAM_BLOCK), heap_get_mem_available(HEAP_TYPE_DRAM_BLOCK), \
            //                     heap_get_mem_usage(HEAP_TYPE_BTDM_BLOCK), heap_get_max_mem_usage_single(HEAP_TYPE_BTDM_BLOCK), heap_get_mem_available(HEAP_TYPE_BTDM_BLOCK), \
            //                     heap_get_max_mem_usage());

        }

        if(backlight_delay_enable)
        {
            if(tick_get - backlight_delay_counter > 200)
            {
                backlight_delay_enable = false;
                rgb_lcd_backlight_set();
            }
        }
       gui_task_auto_suspend();
        
    }
}


#define display_framebuffer2        (void *)PSRAM_DAC_BASE
void app_lvgl_init(void)
{

#if ENABLE_PSRAM
    //hw_psram_init(false);
    //printf("PSRAM ID is 0x%08x.\r\n", psram_read_id());

    // //test psram write & read
	// memset((void *)display_framebuffer2,0x5a,100);
	// uint8_t *test_psram = display_framebuffer2;
	// for(uint32_t i=0;i<(100);i++)
	// {
	// 	printf("%x ",test_psram[i]);
	// }

#endif

    /* create gui relative task. */
	xTaskCreate(gui_task, "gui_task", GUI_TASK_STACK_SIZE, NULL, GUI_TASK_PRIORITY, &gui_task_Handle );
}

// void dma1_irq(void)
// {
//     if (dma_get_tfr_Status(&dma_display_handle)) {
//         display_update_dma_isr();
        
//         display_dma_ongoing = false;
//         my_disp_flush_done();
//         system_prevent_sleep_clear(SYSTEM_PREVENT_SLEEP_DISPLAY_ONGOING);
//     }
// }


void gpiob_irq(void)
{
    printf("this is gpiob irq\r\n");
    // if(exti_get_LineStatus(GPIOB,0xFFFF))
    // {
    //     exti_clear_LineStatus(GPIOB,0xFFFF);
    // }
	// if(exti_get_LineStatus(GPIOB,EXTI_LINE_11))
	// {
	// 		exti_clear_LineStatus(GPIOB,EXTI_LINE_11);
	// 		printf("this is portb exti line 11 \r\n");
	// 		i2c_memory_read(&i2c_touchpad_handle, (0x71) , 0x00, buffer, 7);
	// 		printf("buff %d %d %d %d %d %d\r\n",buffer[0],buffer[1],buffer[3],buffer[4],buffer[5],buffer[6]);
	// }
    // if(exti_get_LineStatus(GPIOB,EXTI_LINE_14))
    // {
    //     exti_clear_LineStatus(GPIOB,EXTI_LINE_14);
    //     //printf("this is portb exti line 14 \r\n");
 
    //     // int16_t x, y;
    //     // touchpad_read(&x, &y);
    //     // printf("tp x:%d,y%d\n",x,y)

    // }
} 

uint32_t * user_get_display_framebuffer(void)
{
    memset((void*)display_framebuffer1,0,DISPLAY_BUFFER_SIZE);
    return (uint32_t *)display_framebuffer1;
}

void * get_display_buffer1(void)
{
    return (uint32_t *)display_framebuffer1;
}